/** * VOComparator - a Comparator for sorting value objects in a VOListValueHolder. * * Copyright (c) 2002 * Marty Phelan, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.taursys.model; import java.util.*; import com.taursys.debug.Debug; /** * <p><code>VOComparator</code> is a <code>Comparator</code> for sorting value * objects in a <code>VOListValueHolder</code>. This can sort by one or more * properties of the value object. Ascending or descending can be specified * for each property (default is ascending). * </p> * <p>To sort by a single property, use the <code>setPropertyName</code> method. * To sort by more than one property use the <code>setPropertyNames</code> * method and pass it a <code>String[]</code> array of property names. * </p> * <p>To change the order for a single property, use the * <code>setAscendingOrder</code> method (<code>true</code>=Ascending * <code>false</code>=descending). To change the order for multiple properties, * use the <code>setAscendingOrders</code> method and pass it a * <code>boolean[]</code> array. The order of the ascending order indicators * should match the array of property names. * </p> * <p>This <code>VOComparator</code> is then attached to the * <code>VOListValueHolder</code> using the <code>setComparator</code> method. * IMPORTANT: This VOComparator can only be used with one VOListValueHolder * at a time - it cannot be shared. * </p> * <p>Example - sort ascending by a lastName</p> * <pre> * VOListValueHolder holder = new VOListValueHolder(); * VOComparator comparator = new VOComparator(); * ... * comparator.setPropertyName("lastName"); * holder.setComparator(comparator); * </pre> * <p>Example - sort ascending by a salary(descending), yearsWorked(ascending)</p> * <pre> * VOListValueHolder holder = new VOListValueHolder(); * VOComparator comparator = new VOComparator(); * ... * comparator.setPropertyNames(new String[] {"salary", "yearsWorked"}); * comparator.setAscendingOrders(new boolean[] {false, true}); * holder.setComparator(comparator); * </pre> * @author Marty Phelan * @version 1.0 */ public class VOComparator implements Comparator { private VOValueHolder holder; private String[] propertyNames; private boolean[] ascendingOrders; private boolean ordering; /** * Constructs a new VOComparator */ public VOComparator() { } /** * Compare the two given value objects based on the <code>propertyName(s)</code> * and <code>ascendingOrder(s)</code>. Return 0 if they are equal, negative * value if <code>o1</code> should appear before <code>o2</code> in the list, * or positive if <code>o1</code> should appear after <code>o2</code> in the * list. If both <code>o1</code> and <code>o2</code> are null, they are * considered equal. If one is null and the other not null, the null value * will appear before the non-null value in the list. The same null rule holds * true for the property values. * @param o1 the object to base the comparison on * @param o2 the object to compare to * @return 0 if o1 and o2 could appear in same position, negative if o1 * should appear before o2, and positive if o1 should appear after o2. */ public int compare(Object o1, Object o2) { // Cannot compare if valueHolder is null - say equals and warn if (holder == null) { Debug.error("VOComparator.compare: Cannot compare - VOValueHolder is null."); return 0; } // Cannot compare if property names are null or empty - say equals and warn if (propertyNames == null || propertyNames.length == 0) { Debug.error("VOComparator.compare: Cannot compare - sort property name(s) is missing."); return 0; } // Do null test first int result = nullTest(o1, o2); // continue if equal if (result == Integer.MAX_VALUE) { // Iterate through properties for (int i = 0; i < propertyNames.length; i++) { // Cannot compare if propertyName is null if (propertyNames[i] == null) { Debug.error("VOComparator.compare: Cannot compare - sort property name #" + i + " is null."); return 0; } else { try { Comparable value1 = (Comparable)holder.getPropertyValue( propertyNames[i], o1); Comparable value2 = (Comparable)holder.getPropertyValue( propertyNames[i], o2); // do null test first result = nullTest(value1, value2); if (result == Integer.MAX_VALUE) { result = value1.compareTo(value2); if (result != 0) return isAscendingOrder(i) ? result : -result; } else { return result; } } catch (ModelException ex) { Debug.error("VOComparator.compare: cannot compare - " + ex.getMessage(), ex); return 0; } } } } return result; } private int nullTest(Object o1, Object o2) { if ((o1 != null && o2 != null)) return Integer.MAX_VALUE; if ((o1 == null && o2 == null)) return 0; if (o1 == null) return -1; else return 1; } /** * Set the VOValueHolder that this comparator is linked to. This holder * provides accessors to the properties of the value object. * @param holder the VOValueHolder that this comparator is linked to. */ public void setVOValueHolder(VOValueHolder holder) { this.holder = holder; } /** * Get the VOValueHolder that this comparator is linked to. This holder * provides accessors to the properties of the value object. * @return the VOValueHolder that this comparator is linked to. */ public VOValueHolder getVOValueHolder() { return holder; } /** * Set the first or only propertyName used for the comparison. * @param propertyName the first or only propertyName used for the comparison. */ public void setPropertyName(String propertyName) { if (propertyNames == null || propertyNames.length == 0) propertyNames = new String[] {propertyName}; else propertyNames[0] = propertyName; } /** * Get the first or only propertyName used for the comparison. * @return the first or only propertyName used for the comparison. */ public String getPropertyName() { if (propertyNames == null || propertyNames.length == 0) return null; else return propertyNames[0]; } /** * Set the ascending order flag for the first or only propertyName. * The default is true. * @param ascendingOrder the ascending order flag for the first or only * propertyName. */ public void setAscendingOrder(boolean ascendingOrder) { if (ascendingOrders == null || ascendingOrders.length == 0) ascendingOrders = new boolean[] {ascendingOrder}; else ascendingOrders[0] = ascendingOrder; } /** * Get the ascending order flag for the first or only propertyName. * The default is true. * @return the ascending order flag for the first or only * propertyName. */ public boolean isAscendingOrder() { return isAscendingOrder(0); } private boolean isAscendingOrder(int index) { if (ascendingOrders == null || ascendingOrders.length <= index) return true; else return ascendingOrders[0]; } /** * Set the propertyNames (in order) used for the comparison. * @param propertyNames the propertyNames (in order) used for the comparison. */ public void setPropertyNames(String[] propertyNames) { this.propertyNames = propertyNames; } /** * Get the propertyNames (in order) used for the comparison. * @return the propertyNames (in order) used for the comparison. */ public String[] getPropertyNames() { return propertyNames; } /** * Set the ascending order flags for each of the properties. * The default is true(ascending) if ommitted. * @param ascendingOrders the ascending order flags for each of the properties. */ public void setAscendingOrders(boolean[] ascendingOrders) { this.ascendingOrders = ascendingOrders; } /** * Get the ascending order flags for each of the properties. * The default is true(ascending) if ommitted. * @return the ascending order flags for each of the properties. */ public boolean[] getAscendingOrders() { return ascendingOrders; } }